package com.serverclient.utility;

import java.io.IOException;
import java.lang.annotation.Annotation;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;

/**
 * 扫描包工具类
 */
public class PackageScanUtility {
	/**
	 * 扫描给定包下的所有的class文件，返回包含指定注解的完整文件名（包含包名和文件名）
	 * @param packages 指定要扫描的包
	 * @param annotationClazz 指定要搜索的注解
	 * @return 
	 */
	public static Set<Class<?>> getClasses(String[] packages,Class<? extends Annotation> annotationClazz){
		if(packages == null || packages.length == 0 || annotationClazz == null){
			return Collections.emptySet();
		}
		
		Set<String> classNameSet = getClassName(packages, ".class");
		if(classNameSet.isEmpty()){
			return Collections.emptySet();
		}
		
		//找出所有携带有指定注解的类模板
		Set<Class<?>> set = new HashSet<Class<?>>();
		for(String className : classNameSet){
			try {
				Class<?> clazz = Class.forName(className);
				//判断是否包含指定的注解
				if(clazz.isAnnotationPresent(annotationClazz)){
					set.add(clazz);
				}
			}catch(ClassNotFoundException e) {
				throw new RuntimeException(e);
			}
		}
		return set;
	}
	
	/**
	 * 获取指定包下面指定文件后缀的文件名集合
	 * @param packages 需要扫描的包
	 * @param fileSuffix 指定的文件后缀，例如.class
	 * @return
	 */
	public static Set<String> getClassName(String[] packages,String fileSuffix){
		if(packages == null || packages.length == 0 || fileSuffix == null || fileSuffix.trim().length() == 0){
			return Collections.emptySet();
		}
		
		Set<String> classNameSet = new HashSet<String>();
		for(String basePackage : packages){
			//扫描包时需要将包名中的.符号替换成文件夹分割符号/，例如com.test.utility变成com/test/utility
			String packageResource = basePackage.replaceAll("\\.", "/");
			
			try {
				//构建Resource查找器，查找指定类路径下的所有class文件
				ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver(Thread.currentThread().getContextClassLoader());
				Resource[] resources = resourcePatternResolver.getResources("classpath*:" + packageResource + "/**/*" + fileSuffix);
				
				//获取所有class文件类名
				MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resourcePatternResolver);
				for(Resource resource : resources){
					MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(resource);
					if(metadataReader != null){
						classNameSet.add(metadataReader.getClassMetadata().getClassName());
					}
				}
			}catch(IOException e) {
				throw new RuntimeException(e);
			}
		}
		return classNameSet;
	}
}
